﻿using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace Futaba.SBus.Extensions
{
	/// <summary>
	/// Provides extension-methods to the <see cref="Object"/> class
	/// </summary>
  public static class ObjectExtensions
  {

		/// <summary>
		/// Generates XML from the supplied instance
		/// </summary>
		/// <typeparam name="T">the type to interpret</typeparam>
		/// <param name="source">the target instance to generate XML from</param>
		/// <param name="encoding">the encoding to use</param>
		/// <param name="knownTypes">a list of known-types used during XML serialization</param>
		/// <returns>XML in string form</returns>
    public static string ToXml<T>(this T source, Encoding encoding, Type[] knownTypes)
    {
      using (var stream = new MemoryStream())
      {
        source.ToXml(stream, encoding, knownTypes);
        stream.Seek(0, SeekOrigin.Begin);
        var output = new StreamReader(stream).ReadToEnd();
        return output;
      }
    }

		/// <summary>
		/// Generates XML from the supplied instance
		/// </summary>
		/// <typeparam name="T">the type to interpret</typeparam>
		/// <param name="source">the target instance to generate XML from</param>
		/// <param name="stream">the stream to write the XML to</param>
		/// <param name="encoding">the encoding to use</param>
		/// <param name="knownTypes">a list of known-types used during XML serialization</param>
		public static void ToXml<T>(this T source, Stream stream, Encoding encoding, Type[] knownTypes)
    {
      using (var writer = XmlWriter.Create(stream, new XmlWriterSettings
      {
#if !WINDOWS_PHONE //TODO: check, if supported by WP8
        Indent = true,
#endif
        Encoding = encoding
      }))
      {
        var serializer = new XmlSerializer(typeof(T), knownTypes);
        serializer.Serialize(writer, source);
        writer.Flush();
        //stream.Seek(0, SeekOrigin.Begin);
      }
    }

		/// <summary>
		/// Generates the specified type from the supplied xml-string
		/// </summary>
		/// <typeparam name="T">the type to generate</typeparam>
		/// <param name="data">the xml-data to deserialize the object from</param>
		/// <param name="knownTypes">a list of known-types used during XML serialization</param>
		/// <returns>the generated/deserialized instance</returns>
		public static T Load<T>(this string data, Type[] knownTypes)
    {
      if (string.IsNullOrEmpty(data))
        throw new ArgumentNullException("data");

      using (var reader = XmlReader.Create(new StringReader(data)))
      {
        return Load<T>(reader, knownTypes);
      }
    }

		/// <summary>
		/// Generates the specified type from the supplied xml-stream
		/// </summary>
		/// <typeparam name="T">the type to generate</typeparam>
		/// <param name="stream">the stream to deserialize the object from</param>
		/// <param name="knownTypes">a list of known-types used during XML serialization</param>
		/// <returns>the generated/deserialized instance</returns>
		public static T Load<T>(this Stream stream, Type[] knownTypes)
    {
      if (stream == null)
        throw new ArgumentNullException("stream");

      using (var reader = XmlReader.Create(stream))
      {
        return Load<T>(reader, knownTypes);
      }
    }

		/// <summary>
		/// Generates the specified type from the supplied xml-stream
		/// </summary>
		/// <typeparam name="T">the type to generate</typeparam>
		/// <param name="reader">the <see cref="XmlReader"/> to deserialize the object from</param>
		/// <param name="knownTypes">a list of known-types used during XML serialization</param>
		/// <returns>the generated/deserialized instance</returns>
		public static T Load<T>(this XmlReader reader, Type[] knownTypes)
    {
      var serializer = new XmlSerializer(typeof(T), knownTypes);
      var output = (T)serializer.Deserialize(reader);
      return output;
    }

  }
}